import re
import random
from datetime import datetime

from fastapi import Request
from pydantic import BaseModel

from schemas.response_entity import JsonModel
from db.repository.user import db_get_user_by_username, db_update_user_token, db_create_user, db_create_user_group, db_restore_user
from db.repository.user_group import db_get_group_by_id_for_permission, db_check_user_in_group
from utils.redis_utils import redis_pool
from utils.sms_client import SMS_CLIENT
from utils.token_utils import create_access_token, get_user_phone_number
from configs import GUEST_GROUP_ID
from loguru import logger


class UserLoginEntity(BaseModel):
    """用户登录实体"""
    username: str  # 可以手机号校验用
    password: str


class UserCreateEntity(BaseModel):
    """创建用户实体"""
    username: str  # 可以手机号校验用
    password: str
    nickname: str = None
    code: str
    company: str = None


class SMSCodeRequest(BaseModel):
    """短信验证码请求实体"""
    username: str


class SMSLoginRequest(BaseModel):
    """短信登录请求实体"""
    username: str
    code: str


# 短信登录请求模型
class WxLoginRequest(BaseModel):
    code: str

async def wx_login(wx_login: WxLoginRequest):
    # 通过 code 获取用户手机号
    username = get_user_phone_number(wx_login.code)

    # 根据手机号查找用户
    user = db_get_user_by_username(username, is_delete=False)
    if not user:
        return JsonModel(code=400, data=None, msg="登录失败，账号信息错误").to_response()

    # 生成 JWT 并更新用户 token
    access_token = create_access_token(data={"name": user.username})
    db_update_user_token(user.id, access_token)
    return JsonModel(code=200, data={"access_token": access_token}, msg=f"用户:{user.nickname}登录成功").to_response(headers={"access_token": access_token})


# token登陆
async def login_with_access_token(payload: UserLoginEntity):
    """
    用户token登录
    
    Args:
        payload: 用户登录数据
        
    Returns:
        JsonModel: 登录结果响应
    """
    user = db_get_user_by_username(payload.username, is_delete=False)
    if not user:
        logger.warning(f"登录失败：用户 {payload.username} 不存在或已删除")
        return JsonModel(code=401, data=None, msg="登录失败，账号信息错误").to_response()
    
    if not user.password:
        logger.error(f"用户 {payload.username} 的密码字段为空")
        return JsonModel(code=401, data=None, msg="登录失败，账号信息错误").to_response()
    
    if not user.verify_password(payload.password):
        logger.warning(f"用户 {payload.username} 密码验证失败")
        return JsonModel(code=401, data=None, msg="登录失败，账号信息错误").to_response()
    
    access_token = create_access_token(data={"name": user.username})
    db_update_user_token(user.id, access_token)
    return JsonModel(code=200, data={"access_token": access_token}, msg=f"用户:{user.nickname}登录成功").to_response(headers={"access_token": access_token})


# 发送验证码
async def send_sms_code(payload: SMSCodeRequest):
    """
    发送短信验证码
    
    Args:
        payload: 短信验证码请求数据
        
    Returns:
        dict: 发送结果
    """
    if not is_valid_phone(payload.username):
        return JsonModel(code=400, data=None, msg="请输入正确的手机号").to_response()

    # 频率限制（示例：60秒内只能发送1次）
    if redis_pool.exists(f"sms_limit:{payload.username}"):
        return JsonModel(code=429, data=None, msg="请求过于频繁").to_response()

    # 生成4位数字验证码
    code = "".join(random.choices("0123456789", k=4))

    # 存储到Redis（5分钟有效期）
    redis_pool.setex(f"sms_code:{payload.username}", 300, code)

    # 记录发送时间（限制频率）
    redis_pool.setex(f"sms_limit:{payload.username}", 60, 1)

    # 调用阿里云短信服务
    success = SMS_CLIENT.send_sms(payload.username, code)
    if not success:
        # 发送失败时删除存储的验证码
        redis_pool.delete(f"sms_code:{payload.username}")
        return JsonModel(code=500, data=None, msg="短信发送失败，请稍后重试").to_response()

    return {"code": 200, "msg": "验证码已发送"}


# 验证码登陆
async def login_with_sms(payload: SMSLoginRequest):
    """
    短信验证码登录
    
    Args:
        payload: 短信登录请求数据
        
    Returns:
        JsonModel: 登录结果响应
    """
    if not is_valid_phone(payload.username):
        return JsonModel(code=400, data=None, msg="请输入正确的手机号").to_response()

    # 验证码校验
    stored_code = redis_pool.get(f"sms_code:{payload.username}")
    if not stored_code or stored_code != payload.code:
        return JsonModel(code=400, data=None, msg=f"验证码错误或已过期").to_response()

    # 查找或创建用户
    user = db_get_user_by_username(payload.username, is_delete=False)
    if not user:
        return JsonModel(code=400, data=None, msg="登录失败，账号信息错误").to_response()

    # 生成访问令牌（复用原有逻辑）
    access_token = create_access_token(data={"name": user.username})

    # 更新用户令牌（根据原有逻辑决定是否需要存储）
    db_update_user_token(user.id, access_token)
    return JsonModel(code=200, data={"access_token": access_token}, msg=f"用户:{user.nickname}登录成功").to_response(headers={"access_token": access_token})


def is_valid_phone(phone: str) -> bool:
    """验证是否为合法手机号(11位数字)"""
    pattern = r'^1[0-9]{10}$'
    return bool(re.match(pattern, phone))


async def register(request: Request, payload: UserCreateEntity):
    """
    用户注册接口
    
    Args:
        request: FastAPI请求对象
        payload: 用户创建数据
        
    Returns:
        JsonModel: 注册结果响应
    """
    # 验证手机号格式
    if not is_valid_phone(payload.username):
        return JsonModel(code=400, data=None, msg="请输入正确的手机号").to_response()

    # 验证码校验
    stored_code = redis_pool.get(f"sms_code:{payload.username}")
    if not stored_code or stored_code != payload.code:
        return JsonModel(code=400, data=None, msg="验证码错误或已过期").to_response()

    # 检查用户是否已存在（包括已删除的用户）
    existing_user = db_get_user_by_username(payload.username)
    if existing_user and not existing_user.is_delete:
        return JsonModel(code=400, data=None, msg="用户已存在").to_response()

    # 密码长度验证
    if len(payload.password) < 6:
        return JsonModel(code=400, data=None, msg="密码长度不能少于6位").to_response()

    try:
        # 如果存在已删除的用户，重新启用
        if existing_user and existing_user.is_delete:
            nickname = payload.nickname if payload.nickname else payload.username
            db_user = db_restore_user(
                username=payload.username,
                nickname=nickname,
                password=payload.password,
                company=payload.company,
                role="normal"
            )
            if db_user is None:
                return JsonModel(code=500, data=None, msg="恢复用户失败").to_response()
        else:
            # 创建新用户
            nickname = payload.nickname if payload.nickname else payload.username
            db_user = db_create_user(
                username=payload.username,
                nickname=nickname,
                password=payload.password,
                company=payload.company,
                role="normal"
            )

        # 将用户添加到游客组（检查组是否存在，并检查用户是否已在组中）
        guest_group = db_get_group_by_id_for_permission(GUEST_GROUP_ID)
        if guest_group is None:
            logger.error(f"游客组（ID: {GUEST_GROUP_ID}）不存在，无法添加用户到组")
            return JsonModel(code=500, data=None, msg=f"系统配置错误：游客组不存在").to_response()
        
        # 检查用户是否已在组中，避免重复添加
        if not db_check_user_in_group(db_user.id, GUEST_GROUP_ID):
            db_create_user_group(db_user.id, GUEST_GROUP_ID)
        
        # 删除验证码
        redis_pool.delete(f"sms_code:{payload.username}")
        
        return JsonModel(code=200, data=None, msg="用户注册成功").to_response()
        
    except Exception as e:
        return JsonModel(code=500, data=None, msg=f"用户注册失败: {str(e)}").to_response()
